package idv.ccApp.cwFileExplore;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.util.Log;
import android.view.*;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ViewFlipper;
import idv.ccApp.cwFileExplore.MuPDFInt.*;
import idv.ccApp.cwFileExplore.PageDrawingInfo;

/**
 * Created with IntelliJ IDEA.
 * User: cc.cheng
 * Date: 2013/6/18
 * Time: 下午 2:50
 * To change this template use File | Settings | File Templates.
 */
public class PdfViewActivity extends Activity  {

  final String TAG = "PdfViewActivity";
  final boolean DEBUG = true;
  private PdfViewActivity THIS;
  private String mPdfFileAbsPath;
  private MuPDFCore mPdfCore = null;
  private MySimpleGestureListener mGestureListener;
  private PageDrawingInfo mCurPageDrawingInfo = new PageDrawingInfo();
  View mCurView;
  View mPreView;
  View mNextView;

  ///////////////////////////
  // for touch event
  Matrix mMatrix = new Matrix();
  Matrix mSavedMatrix = new Matrix();
  PointF mStartPoiont = new PointF();
  PointF mMidPoint = new PointF();
  float mOldDist = 1.0f;
  static final int NONE = 0;
  static final int DRAG = 1;
  static final int ZOOM = 2;
  int mMode = NONE;
  VelocityTracker mVelocityTracker;
  PdfDrawPageAsyncTask mPdfDrawAsyncTask = null;
  Bitmap mNewlyBitmap;
  /////////////////////////////////////////////////////////////////////////
  //
  final Runnable drawPageRunnable = new Runnable() {
    @Override
    public void run() {
      myUtilClass.MyTRACE();
      PageDrawingInfo obj = mCurPageDrawingInfo;
      Bitmap newlyBitmap = mPdfCore.drawPage(
        obj.mPage,
        obj.mWidth,
        obj.mHeight,
        obj.mPatchX,
        obj.mPatchY,
        obj.mPatchW,
        obj.mPatchH
      );
      updatePageDrawingInfo(PageDrawingInfo.PAGE_INFO_ITEM_ENUM.ITEM_BMP, (Object) newlyBitmap);
      reloadPdfPage();
    }
  };

  OnTaskCompleted mPdfcoreDrawPageTaskComplete = new OnTaskCompleted() {
    @Override
    public void onTaskCompleted(Bitmap newBmp) {
      //mCurPageDrawingInfo.mBmpHolder.drop();
      updatePageDrawingInfo(PageDrawingInfo.PAGE_INFO_ITEM_ENUM.ITEM_BMP, (Object) newBmp);
      reloadPdfPage();
      myUtilClass.MyTRACE();

      if(mPdfDrawAsyncTask!=null){
        myUtilClass.MyTRACE();
        mPdfDrawAsyncTask = null;
      }
    }
  };

  View.OnTouchListener mOnTouchListeren = new View.OnTouchListener() {
    private void caculate_zoom_scale(MotionEvent e) {
      float scale = 0.0f;
      float newDist = 0.0f;
      if (e.getPointerCount() >= 2) {
        newDist = getTwoFingerDistance(e);
        if (newDist > 5.0f) {
          //mMatrix.set(mSavedMatrix);
          scale = (newDist / mOldDist);
          //mMatrix.postScale(scale, scale, mMidPoint.x, mMidPoint.y);
        }
        Log.e(TAG, "finger distance:" + Float.toString(newDist) + ", scale:" + Float.toString(scale));

        THIS.updatePageDrawingInfo(PageDrawingInfo.PAGE_INFO_ITEM_ENUM.ITEM_SCALE_FACTOR, scale);
        THIS.reloadPdfPage();
      }
    }

    private void finger_move(View v, MotionEvent e) {
      if (mVelocityTracker == null) {
        Log.e(TAG, "xxvvelocity is null");
      }
      mVelocityTracker.addMovement(e);
      if (mMode == DRAG) {
        mMatrix.set(mSavedMatrix);
        if (v.getLeft() >= -392) {
          mMatrix.postTranslate(e.getX() - mStartPoiont.x, e.getY() - mStartPoiont.y);
        }
      } else if (mMode == ZOOM) {
        this.caculate_zoom_scale(e);
      }
    }

    private void finger_up(MotionEvent e) {
      if ((e.getAction() & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_UP) {
        if (mVelocityTracker == null) {
          Log.e(TAG, "vvelocity is null");
        }
        mVelocityTracker.addMovement(e);
        mVelocityTracker.computeCurrentVelocity(1);
        float a = mVelocityTracker.getXVelocity();
        float b = mVelocityTracker.getYVelocity();

        mVelocityTracker.recycle();
        mVelocityTracker = null;
        mMode = NONE;
        if(THIS.mPdfDrawAsyncTask!=null)
          THIS.mPdfDrawAsyncTask.cancel(true);
      }
    }
    private void multi_finger_down(MotionEvent e) {
      mOldDist = getTwoFingerDistance(e);
      Log.e(TAG, "mVelocityTracker.......");
      if (mOldDist > 5.0f) {
        //mSavedMatrix.set(mMatrix);
        setMidPoint(mMidPoint, e);
        mMode = ZOOM;
      }
    }
    @Override
    public boolean onTouch(View v, MotionEvent e) {
      float scale;
      switch (e.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN: {
          mSavedMatrix.set(mMatrix);
          mStartPoiont.set(e.getX(), e.getY());
          mMode = DRAG;
          mVelocityTracker = VelocityTracker.obtain();
        }
        break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_POINTER_1_UP: {
          this.finger_up(e);
        }
        break;
        case MotionEvent.ACTION_POINTER_DOWN: {
          this.multi_finger_down(e);
        }
        break;
        case MotionEvent.ACTION_MOVE: {
          this.finger_move(v, e);
          ((ImageView) v).setImageMatrix(mMatrix);
        }
        break;
        default: {
        }
        break;
      }
      //((ImageView) v).setImageMatrix(mMatrix);
      return true;
    }
  };
  private float getTwoFingerDistance(MotionEvent e) {
    float x = e.getX(0) - e.getX(1);
    float y = e.getY(0) - e.getY(1);
    return FloatMath.sqrt(x * x + y * y);
  }
  private void setMidPoint(PointF point, MotionEvent e) {
    float x = e.getX(0) - e.getX(1);
    float y = e.getY(0) - e.getY(1);
    point.set(x / 2, y / 2);
  }
  private ViewFlipper getViewFlipper() {
    return (ViewFlipper) this.findViewById(R.id.id_view_Flipper);
  }
  private void updatePageDrawingInfo(PageDrawingInfo.PAGE_INFO_ITEM_ENUM which, Object obj ){
    switch(which){
      case ITEM_BMP:{
        this.mCurPageDrawingInfo.mBmpHolder.drop();
        this.mCurPageDrawingInfo.mBmpHolder.setBm((Bitmap)obj);
      } break;
      case ITEM_BMP_HOLDER:{
        this.mCurPageDrawingInfo.mBmpHolder.drop();
        this.mCurPageDrawingInfo.mBmpHolder = (BitmapHolder)obj;
      } break;
    }
  }
  Handler mh;
  private void updatePageDrawingInfo(PageDrawingInfo.PAGE_INFO_ITEM_ENUM which, float data ){
    switch (which){
      case ITEM_HEIGHT:{
        this.mCurPageDrawingInfo.mHeight = (int)data;
      } break;
      case ITEM_WIDTH:{
        this.mCurPageDrawingInfo.mWidth = (int)data;
      } break;
      case ITEM_PATCH_X:{
        this.mCurPageDrawingInfo.mPatchX = (int)data;
      } break;
      case ITEM_PATCH_Y:{
        this.mCurPageDrawingInfo.mPatchY = (int)data;
      } break;
      case ITEM_PATCH_H:{
        this.mCurPageDrawingInfo.mPatchH = (int)data;
      } break;
      case ITEM_PATCH_W:{
        this.mCurPageDrawingInfo.mPatchW = (int)data;
      } break;
      case ITEM_SCALE_FACTOR:{
        int h,w,ph,pw;

        if(this.mPdfDrawAsyncTask!=null){
          if(this.mPdfDrawAsyncTask.getStatus().equals(AsyncTask.Status.PENDING)){
            this.mPdfDrawAsyncTask.execute(this.mCurPageDrawingInfo);
          }
          break;
        }
        this.mCurPageDrawingInfo.mScaleFactor = data;
        float ratio = this.mCurPageDrawingInfo.mPageAspect;
        //float ratio = this.mCurPageDrawingInfo.mScreenAspect;
        int magic = 50;
        if ( data<1.0f){
          //ph = h = (int)(((float)this.mCurPageDrawingInfo.mHeight)*0.8);
          //pw = w  = (int)(((float)this.mCurPageDrawingInfo.mWidth)*0.8);
          ph = h = (int)(((float)this.mCurPageDrawingInfo.mHeight))-magic;
          pw = w  = (int)(((float)this.mCurPageDrawingInfo.mWidth))-((int)((float)magic/ratio));
        } else {
          //ph = h = (int)(((float)this.mCurPageDrawingInfo.mHeight)*1.2);
          //pw = w  = (int)(((float)this.mCurPageDrawingInfo.mWidth)*1.2);
          ph = h = (int)(((float)this.mCurPageDrawingInfo.mHeight))+magic;
          pw = w  = (int)(((float)this.mCurPageDrawingInfo.mWidth))+((int)((float)magic/ratio));
        }

        if ( h<this.mCurPageDrawingInfo.mMinHeight
          || h>this.mCurPageDrawingInfo.mMaxHeight
          || w<this.mCurPageDrawingInfo.mMinWidth
          || w>this.mCurPageDrawingInfo.mMaxWidth
           )
        {
          myUtilClass.MyTRACE("\nthe picture size is not valid\n" +
            " h:" + Integer.toString(h) +
            " w:" + Integer.toString(w) +
            " mh:" + Integer.toString(this.mCurPageDrawingInfo.mMinHeight) +
            " mw:" + Integer.toString(this.mCurPageDrawingInfo.mMinWidth) +
            " Mh:" + Integer.toString(this.mCurPageDrawingInfo.mMaxHeight) +
            " Mw:" + Integer.toString(this.mCurPageDrawingInfo.mMaxWidth)
          );
          break;
        }

        this.mCurPageDrawingInfo.mHeight = h;
        this.mCurPageDrawingInfo.mWidth  = w;
        this.mCurPageDrawingInfo.mPatchH = ph;
        this.mCurPageDrawingInfo.mPatchW = pw;
        if(mh==null)
          mh = new Handler();
        mh.postDelayed(this.drawPageRunnable,1);

/*
        this.mPdfDrawAsyncTask = new PdfDrawPageAsyncTask(this.mPdfcoreDrawPageTaskComplete, this.mPdfCore);

        Log.e(TAG, "scale:" + Float.toString(data));
        Log.e(TAG, " org->"
          + " Height:" + Integer.toString(this.mCurPageDrawingInfo.mHeight)
          + " Width:" + Integer.toString(this.mCurPageDrawingInfo.mWidth)
          + " PatchH:" + Integer.toString(this.mCurPageDrawingInfo.mPatchH)
          + " PatchW:" + Integer.toString(this.mCurPageDrawingInfo.mPatchW)
          + " x:" + Integer.toString(this.mCurPageDrawingInfo.mPatchX)
          + " y:" + Integer.toString(this.mCurPageDrawingInfo.mPatchY)
        );

        this.mCurPageDrawingInfo.mHeight = h;
        this.mCurPageDrawingInfo.mWidth  = w;
        this.mCurPageDrawingInfo.mPatchH = ph;
        this.mCurPageDrawingInfo.mPatchW = pw;

        Log.e(TAG, "new->"
          + " Height:" + Integer.toString(this.mCurPageDrawingInfo.mHeight)
          + " Width:" + Integer.toString(this.mCurPageDrawingInfo.mWidth)
          + " PatchH:" + Integer.toString(this.mCurPageDrawingInfo.mPatchH)
          + " PatchW:" + Integer.toString(this.mCurPageDrawingInfo.mPatchW)
          + " x:" + Integer.toString(this.mCurPageDrawingInfo.mPatchX)
          + " y:" + Integer.toString(this.mCurPageDrawingInfo.mPatchY)
        );

        //if(this.mPdfDrawAsyncTask.getStatus().equals(AsyncTask.Status.FINISHED))
          this.mPdfDrawAsyncTask.execute(this.mCurPageDrawingInfo);
        this.mPdfDrawAsyncTask = null;
*/
        /*
        Bitmap newBmp = this.mPdfCore.drawPage(
          this.mCurPageDrawingInfo.mPage,
          this.mCurPageDrawingInfo.mWidth,
          this.mCurPageDrawingInfo.mHeight,
          this.mCurPageDrawingInfo.mPatchX,
          this.mCurPageDrawingInfo.mPatchY,
          this.mCurPageDrawingInfo.mPatchW,
          this.mCurPageDrawingInfo.mPatchH
        );
        */

        //this.mCurPageDrawingInfo.mBmpHolder.drop();
        //this.updatePageDrawingInfo(PageDrawingInfo.PAGE_INFO_ITEM_ENUM.ITEM_BMP, (Object)newBmp);
      } break;
      default: {
        myUtilClass.MyTRACE("should not here");
      } break;
    }
  }

  private void loadDefaultPdfPage(){
    DisplayMetrics metrics = myUtilClass.getDisplayMatrix(this);
    int w,h,x,y,pw,ph,page;
    page = 0;
    x = y = 0;
    w = (int)(((float)metrics.widthPixels)*1.0);
    h = (int)(((float)metrics.heightPixels)*1.0);
    pw=w;
    ph=h;

    Bitmap bm0 = this.mPdfCore.drawPage(page, w, h, x, y, pw, ph);

    this.mCurPageDrawingInfo.mBmpHolder.setBm(bm0);
    this.mCurPageDrawingInfo.mHeight = h;
    this.mCurPageDrawingInfo.mWidth = w;
    this.mCurPageDrawingInfo.mPatchX = x;
    this.mCurPageDrawingInfo.mPatchY = y;
    this.mCurPageDrawingInfo.mPatchH = ph;
    this.mCurPageDrawingInfo.mPatchW = pw;
    this.mCurPageDrawingInfo.mPage = page;
    this.mCurPageDrawingInfo.mScaleFactor = 1.0f;

    ((MyImageView) this.mCurView.findViewById(R.id.id_image_page_view)).setImageBitmap(bm0);
    ((MyImageView) this.mCurView.findViewById(R.id.id_image_page_view)).setOnTouchListener(this.mOnTouchListeren);

    PointF p = this.mPdfCore.getPageSize(1);
    myUtilClass.MyTRACE("x:" + Float.toString(p.x) + ",y:"+Float.toString(p.y)+",length:"+p.length());
    this.mCurPageDrawingInfo.mPageAspect = p.y/p.x;
    this.mCurPageDrawingInfo.mScreenAspect = metrics.heightPixels/metrics.widthPixels;

    this.mCurPageDrawingInfo.mMinHeight = metrics.heightPixels/4;
    this.mCurPageDrawingInfo.mMaxHeight = metrics.heightPixels*4;
    this.mCurPageDrawingInfo.mMinWidth = metrics.widthPixels/4;
    this.mCurPageDrawingInfo.mMaxWidth = metrics.widthPixels*4;

  }

  private void initViewFlipper() {
    try {
      //Inflate the Views
      LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      this.mCurView = inflater.inflate(R.layout.single_page, null);
      this.getViewFlipper().addView(this.mCurView);
    } catch (Exception e) {
      Log.e(TAG, "gggaanew object error: [MuPDFCore]");
    }
    /////////////////////////
    PointF p = this.mPdfCore.getPageSize(1);
    myUtilClass.MyTRACE("x:" + Float.toString(p.x) + ",y:"+Float.toString(p.y)+",length:"+p.length());
  }
  private void reloadPdfPage(){
    ((MyImageView) this.mCurView.findViewById(R.id.id_image_page_view)).setImageBitmap(this.mCurPageDrawingInfo.mBmpHolder.getBm());
  }
  @Override
  protected void onDestroy() {
    myUtilClass.switchFulllScreen(this, false);
    super.onDestroy();
  }
  public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    myUtilClass.switchFulllScreen(this, true);
    setContentView(R.layout.pdf_page_view);

    this.THIS = (PdfViewActivity)this;
    try {
      Intent intent = this.getIntent();
      this.mPdfFileAbsPath = intent.getStringExtra(parameterClass.PARA_PDF_FILE_PATH);
      myUtilClass.MyTRACE(this.mPdfFileAbsPath);

      if (this.mPdfCore == null) {
        this.mPdfCore = new MuPDFCore(this, this.mPdfFileAbsPath);
      }
      /*
      if(this.mPdfCore != null){
        this.mPdfDrawAsyncTask = new PdfDrawPageAsyncTask(this.mPdfcoreDrawPageTaskComplete, this.mPdfCore);
      }
*/
      // it is strange that we have to get pages first, to avoid mupdf.so crash
      this.mPdfCore.countPages();

      //this.initGestureDetector();
      this.initViewFlipper();
      this.loadDefaultPdfPage();
      this.getViewFlipper().showNext();

    } catch (Exception e) {
      Log.e(TAG, "new object error: [MuPDFCore], " + e.toString());
    }
  }
}
